/* eslint-disable prettier/prettier */
import {
  CubeTextureLoader,
  BufferGeometry,
  Line,
  ExtrudeGeometry,
  Mesh,
  MeshStandardMaterial,
  EdgesGeometry,
  LineBasicMaterial,
  LineSegments,
  CanvasTexture,
  SpriteMaterial,
  Sprite,
  Group,
  DoubleSide,
  BackSide
} from 'three'

class SVGModel {
  constructor() {
    // 加载立方体纹理
    this.textureCube = new CubeTextureLoader().setPath('hdrimg/').load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg'])
  }

  // 设置挤压高度等参数
  heightSetting(height) {
    return {
      steps: 1,
      depth: -height,
      bevelEnabled: false,
      bevelThickness: 1,
      bevelSize: 1,
      bevelOffset: 0,
      bevelSegments: 1
    }
  }

  // 处理svg格式数据，将svg挤压成立体模型
  svgSqueezeHeight(shapes, y = 0, height = 1, material, path, border = false, line = false, name) {
    const result = []
    for (let shape of shapes) {
      if (line) {
        // 处理线的情况
        shape.autoClose = true
        const points = shape.getPoints()
        const geometry = new BufferGeometry().setFromPoints(points)
        const lineMesh = new Line(geometry, material)
        lineMesh.rotation.x = Math.PI / 2
        lineMesh.position.y = y
        result.push(lineMesh)
      } else {
        // 处理面（非线）的情况
        const geometry = new ExtrudeGeometry(shape, this.heightSetting(height))
        const mesh = new Mesh(geometry, material)
        if (name) {
          mesh.name = name
        }
        mesh.rotation.x = Math.PI / 2
        mesh.position.y = y
        if (border) {
          // 添加边界线
          const edges = new EdgesGeometry(mesh.geometry, 45)
          const edgesMaterial = new LineBasicMaterial({
            color: path.color,
            transparent: true,
            opacity: 0.5,
            depthWrite: false
          })
          const line = new LineSegments(edges, edgesMaterial)
          mesh.add(line)
        }
        result.push(mesh)
      }
    }
    return result
  }

  // 解析SVG属性，将其转换为位置对象
  svgAttribute(svg) {
    if (svg.length > 0) {
      const regex = /\((.+?)\)/g
      const options = svg[0].value.match(regex)[0]
      const matrixNum = options.substring(1, options.length - 1).split(' ')
      return {
        xup: Number(matrixNum[0]),
        yup: Number(matrixNum[1]),
        zup: Number(matrixNum[2]),
        x: Number(matrixNum[4]),
        y: Number(matrixNum[3]),
        z: Number(matrixNum[5])
      }
    }
    return null
  }

  // 添加精灵（文字或图标）
  addSprite(name, position, isText) {
    const canvas = document.createElement('canvas')
    canvas.width = 200
    canvas.height = 40
    const context = canvas.getContext('2d')
    const texture = new CanvasTexture(canvas)

    if (isText) {
      // 绘制文字
      context.lineWidth = 5
      context.font = '28px Arial'
      context.strokeStyle = '#ffffff'
      context.textAlign = 'left'
      context.textBaseline = 'middle'
      context.strokeText(name, 44, 20)
      context.fillStyle = '#333'
      context.fillText(name, 44, 20)
      texture.needsUpdate = true
    } else {
      // 绘制图标
      const img = new Image()
      img.src = `img/icon/icon_${name}.png`
      img.onload = () => {
        context.drawImage(img, 0, 0, 40, 40)
        context.lineWidth = 5
        context.font = '28px Arial'
        context.strokeStyle = '#ffffff'
        context.textAlign = 'left'
        context.textBaseline = 'middle'
        context.strokeText(name, 44, 20)
        context.fillStyle = '#333'
        context.fillText(name, 44, 20)
        texture.needsUpdate = true
      }
    }

    const spriteMaterial = new SpriteMaterial({
      map: texture,
      transparent: true,
      depthWrite: false,
      sizeAttenuation: false
    })

    const sprite = new Sprite(spriteMaterial)
    sprite.name = name
    sprite.renderOrder = 1
    sprite.scale.set(0.15, 0.03, 0.0)

    if (isText) {
      sprite.center.set(0.3, 0)
      sprite.position.set(position.x, 46, position.z)
    } else {
      sprite.position.set(position.x, 46, position.z)
      sprite.center.set(0.02, 0)
    }

    return sprite
  }

  // 将SVG数据转换为Three.js模型
  svgToModel(data, name, id, spiritName) {
    const paths = data.paths
    const spiritGroup = new Group()
    spiritGroup.name = spiritName
    const svgGroup = new Group()
    svgGroup.position.y = id * 200 - 200
    svgGroup.name = name

    // 处理文字
    if (data.xml.children.text) {
      const textList = data.xml.children.text.children
      for (let textElement of textList) {
        const value = textElement.attributes
        const text = textElement.innerHTML
        const textPosition = this.svgAttribute(value)
        if (textPosition) {
          spiritGroup.add(this.addSprite(text, textPosition, true))
        }
      }
    }

    // 处理图标
    if (data.xml.children.icon) {
      const iconList = [...data.xml.children.icon.children]
      for (let iconElement of iconList) {
        const iconName = iconElement.firstElementChild.innerHTML
        const iconPosition = this.svgAttribute(iconElement.firstElementChild.attributes)
        if (iconPosition) {
          spiritGroup.add(this.addSprite(iconName, iconPosition, false))
        }
      }
    }

    // 处理点线面，将点线面转换为立体模型
    for (let path of paths) {
      const svgNameList = path.userData.node.parentNode.id.split('_') || path.userData.node.parentNode.id
      const svgName = svgNameList.length > 0 ? svgNameList[0] : null
      const material = new MeshStandardMaterial({
        color: path.color,
        side: DoubleSide,
        envMap: this.textureCube,
        metalness: 0.4,
        roughness: 0.96
      })
      const opacityMaterial = new MeshStandardMaterial({
        color: path.color,
        side: BackSide,
        envMap: this.textureCube,
        metalness: 0.5,
        roughness: 0.96,
        transparent: true,
        opacity: 0.8,
        depthWrite: false
      })

      const backShapes = path.toShapes(true, true)
      let exHeight = 1
      if (svgName === 'plant' || svgName === 'guide' || svgName === 'metope') {
        exHeight = parseInt(path.userData.node.parentNode.id.split('_ex')[1], 10) || 1
      }

      const models = this.svgSqueezeHeight(
        backShapes,
        -4,
        exHeight,
        material,
        path,
        svgName === 'guide' || svgName === 'metope',
        svgName === 'background' || svgName === 'boundary'
      )

      models.forEach(model => svgGroup.add(model))
    }

    svgGroup.add(spiritGroup)
    return svgGroup
  }
}

export { SVGModel }
